package com.web.music.impl;

import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;

import com.web.music.common.MusicException;
import com.web.music.interfaces.HTTPClient;

public class ApacheHTTPClient implements HTTPClient {

	private static final String DEFAULT_FILE_EXT = ".xml";

	private Map<String, String> configurationSettings;	// proxy configuration settings
	
	public InputStream downloadToInputStream(String url){
		byte[] page = download(url);
		return new ByteArrayInputStream(page);
	}
	
	public String downloadToFile(String url) 
	{
		byte[] page = download(url);
		try {
			// try to extract file extension from URL
			int lastDotIndex = url.lastIndexOf(".");
			String fileExtension = null;
			if (lastDotIndex >= 0){
				fileExtension = url.substring(lastDotIndex, url.length());
			}
			else{
				// otherwise use default extension
				fileExtension = DEFAULT_FILE_EXT;
			}
			
			// generate temporary file name using URL hash code
			String fileName = (new Integer(url.hashCode())).toString() + fileExtension;
			
			OutputStream ostream = new FileOutputStream(fileName);
			ostream.write(page);
			ostream.flush();
			ostream.close();
			return fileName;	// file is saved, return name of file
		} catch (Exception e) {
			System.err.println("Error while saving page on disc");
			throw new MusicException(e);
		}		
	}

	/**
	 * Downloads page content from provided URL and returns it as byte array
	 * 
	 * @param url
	 * @return byte array representing downloaded page
	 */
	private byte[] download(String url) {
		System.out.println("Starting to download from URL [" + url + "]");

		// create HTTL client instance
		HttpClient client = new HttpClient();

		// if proxy configuration settings are specified, then apply them
		if (configurationSettings != null){
			HostConfiguration configuration = new HostConfiguration();
			configuration.setProxy(
					 configurationSettings.get("http.proxyHost"), 
					 Integer.parseInt(configurationSettings.get("http.proxyPort")));
			client.setHostConfiguration(configuration);
		}

		// create method for HTTP request
		GetMethod method = new GetMethod(url);

		// set some specific parameters
		method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
				new DefaultHttpMethodRetryHandler(3, false));

		try {
			int statusCode = client.executeMethod(method);	// execute method
			if (statusCode != HttpStatus.SC_OK) {				
				throw new MusicException("Method failed: " + method.getStatusLine());
			}
			// get response body with downloaded page
			return method.getResponseBody();	
		} catch (HttpException e1) {
			System.err.println("Fatal protocol violation: " + e1.getMessage());
			throw new MusicException(e1);
		} catch (IOException e2) {
			System.err.println("Fatal transport error: " + e2.getMessage());
			throw new MusicException(e2);
		} finally {
			method.releaseConnection();
		}
	}

	public Map<String, String> getConfigurationSettings() {
		return configurationSettings;
	}

	public void setConfigurationSettings(Map<String, String> configurationSettings) {
		this.configurationSettings = configurationSettings;
	}
}
